package ru.usu.gv.utils.imports;

import org.w3c.dom.Document;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;

import ru.usu.gv.graph.Graph;
import ru.usu.gv.graph.Vertex;
import ru.usu.gv.gui.actions.ChangeGraphDirectionAction;
import ru.usu.gv.utils.XmlUtil;
import ru.usu.gv.utils.generators.ClusterGenerator.VertexCreator;

import java.util.HashMap;
import java.util.Map;

/**
 @author Sergey Pupyrev 
 Jun 25, 2006
 */
public class SimpleGraphImporter implements IGraphXmlConstants
{
	public static Graph loadGraph(String path, VertexCreator creator) throws XmlParseException
	{
		try
		{
			System.out.print("Start importing graph (" + path + ")...");

			Node graphRootElement = readRootElement(path, GRAPH_NODE);
			//directed
			boolean directed = XmlUtil.readBooleanAttribute(graphRootElement, GRAPH_DIRECTED_ATTRIBUTE);
			new ChangeGraphDirectionAction(directed).execute();

			Graph graph = new Graph();
			Map<String, Vertex> idToVertex = new HashMap();

			//vertexes
			NodeList nodes = XmlUtil.getChildsByTagName(graphRootElement, VERTEX_NODE);
			importNodes(graph, directed, nodes, idToVertex, creator);

			//edges
			nodes = XmlUtil.getChildsByTagName(graphRootElement, EDGE_NODE);
			importEdges(graph, directed, nodes, idToVertex);

			System.out.println("ok");
			return graph;
		}
		catch (XmlParseException e)
		{
			throw e;
		}
		catch (Exception e)
		{
			throw new XmlParseException(e);
		}
	}

	private static Node readRootElement(String path, String rootNode) throws Exception, XmlParseException
	{
		return readRootElement(path, rootNode, true);
	}

	private static Node readRootElement(String path, String rootNode, boolean mandatory) throws Exception, XmlParseException
	{
		Document root = XmlUtil.loadXmlFile(path);
		NodeList rootElemets = root.getElementsByTagName(rootNode);
		if (rootElemets.getLength() != 1)
		{
			if (mandatory)
				throw new XmlParseException("Wrong number of root elemts: " + rootElemets.getLength());
			else
				return null;
		}
		return rootElemets.item(0);
	}

	private static void importNodes(Graph graph, boolean directed, NodeList nodes, Map<String, Vertex> idToVertex, VertexCreator creator) throws Exception
	{
		int count = nodes.getLength();
		for (int i = 0; i < count; i++)
		{
			Node node = nodes.item(i);
			String id = XmlUtil.readStringAttribute(node, VERTEX_ID);

			Vertex v = creator.createVertex();
			graph.addVertex(v);
			idToVertex.put(id, v);
		}
	}

	private static void importEdges(Graph graph, boolean directed, NodeList nodes, Map<String, Vertex> idToVertex) throws Exception, XmlParseException
	{
		int edgeCount = nodes.getLength();
		for (int i = 0; i < edgeCount; i++)
		{
			Node node = nodes.item(i);
			String begin = XmlUtil.readStringAttribute(node, EDGE_BEGIN);
			String end = XmlUtil.readStringAttribute(node, EDGE_END);

			Vertex v1 = idToVertex.get(begin);
			Vertex v2 = idToVertex.get(end);
			if (v1 == null)
				throw new XmlParseException("Can't find node with id='" + begin + "'");
			if (v2 == null)
				throw new XmlParseException("Can't find node with id='" + end + "'");

			if (!directed)
			{
				graph.addEdge(v1, v2);
				graph.addEdge(v2, v1);
			}
		}
	}

}
